#ifndef PoseBlenderAim_h
#define PoseBlenderAim_h

#include <CryExtension/Impl/ClassWeaver.h>


struct SDirInfo 
{
#if defined(__CRYCG__)	
	SDirInfo(){ /*dummy for crycg*/}
#endif

	int16	m_numDirPoses;
	int16	m_pad;
	int16	m_nGlobalDirID0;
	int16	m_nGlobalDirID1;
	f32		m_fWeight;
	f32		m_fAnimTime;
};



struct DBW
{
	uint32	m_nAnimTokenCRC32; 
	int32		m_nParaJointIdx; 
	int32		m_nStartJointIdx;
	f32			m_fWeight;
	DBW() {
		m_nAnimTokenCRC32=0; 
		m_nParaJointIdx=-1; 
		m_nStartJointIdx=-1;
		m_fWeight=0;
	}
};


struct SDirectionalBlender
{

	SDirectionalBlender() { Init(); }
	bool ExecuteDirectionalIK(const SAnimationPoseModiferParams& params,DirectionalBlends* rDirBlends,uint32 numDB, SJointsAimIK_Rot* rRot,uint32 numRotJoints, SJointsAimIK_Pos* rPos,uint32 numPosJoints,const ColorB& col );
	void AccumulateAimPoses(const SAnimationPoseModiferParams& params, GlobalAnimationHeaderAIM& rAIM, QuatT* arrRelPose, f32 fIKBlend, const Vec3& rAimTarget, int32 widx,int32 nStartJointIdx,  SJointsAimIK_Rot* rRot,uint32 numRotJoints,  SJointsAimIK_Pos* rPos,f32 CosineY,uint32 sides, const ColorB& col  );
	void DebugVEGrid(const SAnimationPoseModiferParams& params, SDirInfo& rAimInfo, f32 fAimPoseWeight, f32 fIKBlend, int32 widx, SJointsAimIK_Rot* rRot,uint32 numRotJoints,  SJointsAimIK_Pos* rPos,uint32 numPosJoints);

	void Init()
	{
		m_Set_UseDirIK=0;
		m_Set_nLayer									= 16;
		m_Set_vDirIKTarget						=	Vec3(ZERO);
		m_Set_fDirIKTargetSmoothTime	= 0.10f;
		m_Set_fDirIKBlend							=	0.0f; //percentage value between animation and aim-ik
		m_Set_fDirIKFadeoutAngle			=	1;
		m_Set_fDirIKFadeOutTime				= 0.6f;
		m_Set_fDirIKFadeInTime				= 0.3f;
		m_Set_PolarCoordinates				= Vec2(0,0);


		m_UseDirIK									= m_Set_UseDirIK;
		m_nDirLayer									= m_Set_nLayer;
		m_vDirIKTarget							= m_Set_vDirIKTarget;
		m_fDirIKTargetSmoothTime		= m_Set_fDirIKTargetSmoothTime;
		m_fDirIKBlend								= m_Set_fDirIKBlend;
		m_fDirIKFadeInTime					= m_Set_fDirIKFadeInTime;
		m_fDirIKFadeOutTime					= m_Set_fDirIKFadeOutTime;
		m_PolarCoordinates					= m_Set_PolarCoordinates;
		m_PolarCoordinatesSmooth		= m_Set_PolarCoordinates;
		m_PolarCoordinatesRate			= m_Set_PolarCoordinates;
		m_fDirIKInfluence						=	0.0f;
		m_fFieldOfViewSmooth				= 1.0f;
		m_fFieldOfViewRate					= 1.0f;
		m_nDirIKFadeout							=	0;
		m_vDirIKTargetSmooth					=	Vec3(ZERO);
		m_vDirIKTargetRate						=	Vec3(ZERO);
		m_numActiveDirPoses					=	0;
		m_nLastValidDirPose					=-1;
		for (uint32 i=0; i<MAX_EXEC_QUEUE*2; i++)
		{
			m_DirInfo[i].m_fWeight				= 0; 
			m_DirInfo[i].m_numDirPoses		= 0; 
			m_DirInfo[i].m_nGlobalDirID0	=-1; 
			m_DirInfo[i].m_nGlobalDirID1	=-1;
			m_DirInfo[i].m_fAnimTime			= 0.0f;
		}
	}

	// Double buffering
	int8		m_Set_UseDirIK;
	int8		m_Set_nLayer;
	Vec3		m_Set_vDirIKTarget;
	f32			m_Set_fDirIKTargetSmoothTime;
	f32			m_Set_fDirIKBlend;
	f32			m_Set_fDirIKFadeoutAngle;
	f32			m_Set_fDirIKFadeInTime;
	f32			m_Set_fDirIKFadeOutTime;
	Vec2		m_Set_PolarCoordinates;

	//--------------------------------------------------

	int8		m_UseDirIK;
	int8		m_numActiveDirPoses;	//active animation in the FIFO queue
	int8		m_nDirLayer;
	int8		m_nDirIKFadeout;				//set and deleted internally
	int32		m_nLastValidDirPose;
	Vec3		m_vDirIKTarget;
	Vec3		m_vDirIKTargetSmooth;
	Vec3		m_vDirIKTargetRate;
	f32			m_fDirIKTargetSmoothTime;
	f32			m_fDirIKBlend;
	f32			m_fDirIKInfluence;
	f32			m_fFieldOfViewSmooth;
	f32			m_fFieldOfViewRate;
	f32			m_fDirIKFadeInTime;
	f32			m_fDirIKFadeOutTime;
	Vec2		m_PolarCoordinates;
	Vec2		m_PolarCoordinatesSmooth;
	Vec2		m_PolarCoordinatesRate;
	SDirInfo m_DirInfo[MAX_EXEC_QUEUE*2]; 


	DBW m_dbw[4];

};



class CPoseBlenderAim : public IAnimationPoseBlenderDir
{
	CRYINTERFACE_BEGIN()
		CRYINTERFACE_ADD(IAnimationPoseModifier)
		CRYINTERFACE_ADD(IAnimationPoseBlenderDir)
		CRYINTERFACE_END()

		CRYGENERATE_CLASS(CPoseBlenderAim, "AnimationPoseModifier_PoseBlenderAim", 0x058c3e18b9574faf, 0x8989b9cb2cff0d64)

		// This interface
public:
	void SetState(bool state) { m_blender.m_Set_UseDirIK = state; }
	void SetTarget(const Vec3& target) { if (target.IsValid()) m_blender.m_Set_vDirIKTarget = target; }
	void SetLayer(uint32 layer) { m_blender.m_Set_nLayer = MAX(layer,1);	}
	void SetBlendTime(f32 time) { if (time != -1.0f) m_blender.m_Set_fDirIKBlend = time; }
	f32 GetBlendTime() { return m_blender.m_Set_fDirIKBlend; }
	void SetFadeoutAngle(f32 a) { m_blender.m_Set_fDirIKFadeoutAngle = a > 0; }
	void SetFadeOutTime(f32 time) { m_blender.m_Set_fDirIKFadeOutTime = time; }
	void SetFadeInTime(f32 time) { m_blender.m_Set_fDirIKFadeInTime = time; }
	void SetTargetSmoothTime(f32 time) { m_blender.m_Set_fDirIKTargetSmoothTime = time; }
	uint32 GetStatus() { return uint32(m_blender.m_Set_UseDirIK && (m_blender.m_fDirIKInfluence > 0.9f)); }
	f32 GetBlend() { return m_blender.m_fDirIKInfluence; }
	void SetPolarCoordinates(const Vec2& pc) 
	{
		m_blender.m_Set_PolarCoordinates = pc;	
	};

	// IAnimationPoseModifier
public:
	virtual bool Prepare(const SAnimationPoseModiferParams& params);
	virtual bool Execute(const SAnimationPoseModiferParams& params);
	virtual void Synchronize();

	void GetMemoryUsage(ICrySizer* pSizer) const 
	{
		pSizer->AddObject(this, sizeof(*this));
	}

public:
	bool Update(const SAnimationPoseModiferParams& params);

public:
	SDirectionalBlender m_blender;
};



#endif // PoseBlenderAim_h
